#pragma once
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <functional>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h>
#include "InetAddr.hpp"
#include "Log.hpp"
const int defaultblock = 8;

using func_t = std::function<std::string(const std:: string& cmd, Inet_Addr& addr)>;
using namespace LogModule;

//服务器不支持拷贝
class TcpServer:public NoCopy
{
    public:
        TcpServer(uint16_t port, func_t f)
        :_port(port),
         _listensockerfd(-1),
         _f(f)
        {

        }
        void Init()
        {
            //signal(SIGCHLD, SIG_IGN);//忽略信号这样进程就不用等待了
            //创建套接字
            _listensockerfd = socket(AF_INET, SOCK_STREAM, 0);
            if(_listensockerfd < 0)
            {
                LOG(LogLevel::FATAL) << "socket error";
                exit(SOCKET_ERR);
            }
            LOG(LogLevel::DEBUG) << "socket success: " << _listensockerfd;

            //绑定套接字
            Inet_Addr peer(_port);
            int n1 = bind(_listensockerfd, peer.INetAddr(), peer.NetAddrLen());
            if(n1 < 0)
            {
                LOG(LogLevel::FATAL) << "bind error";
                exit(BIND_ERR);
            }
            LOG(LogLevel::DEBUG) << "bind success: " << _listensockerfd;

            //监听链接
            int n2 = listen(_listensockerfd, defaultblock);
            if(n2 < 0)
            {
                LOG(LogLevel::FATAL) << "listen error";
                exit(LISTEN_ERR);
            }
            LOG(LogLevel::DEBUG) << "listen success: " << _listensockerfd;

        }
        void fun(int sockfd, Inet_Addr addr)
        {
            
            while(true)
            {
                char buffer[1024];
                int n = read(sockfd, buffer, sizeof buffer);
                if(n > 0)
                {
                    buffer[n] = 0;
                    LOG(LogLevel::INFO) << "client say# " << buffer;
                    std::string echo = _f(buffer, addr);
                    write(sockfd, echo.c_str(), echo.size());
                }
                else if(n == 0)
                {
                    LOG(LogLevel::DEBUG) << "client关闭...";
                    close(sockfd);
                    break;
                }
                else{
                    LOG(LogLevel::DEBUG) << "异常...";
                    close(sockfd);
                    break;
                }
            }
        }

        class ThreadData 
        {
            public:
            ThreadData(int sockfd, Inet_Addr addr, TcpServer* t)
            :_sockfd(sockfd),_addr(addr),_this(t)
            {

            }
            
            int _sockfd;
            Inet_Addr _addr;
            TcpServer *_this;
        };

        static void* Routine(void* args)
        {
            
            //先与主线程分离,这样主线程不用等待子线程
            pthread_detach(pthread_self());
            ThreadData* td = static_cast<ThreadData*>(args);
            td->_this->fun(td->_sockfd, td->_addr);
            delete td;
            return nullptr;
        }
        void Run()
        {

            while(true)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(sockaddr_in);//1

                // int flags = fcntl(_listensockerfd, F_GETFL, 0);
                // fcntl(_listensockerfd, F_SETFL, flags & ~O_NONBLOCK);
                int sockfd = accept(_listensockerfd, COVN(peer), &len);
                if(sockfd < 0)
                {
                    LOG(LogLevel::WARNING) << "accept error";
                    continue;
                }
                Inet_Addr addr(peer);
                LOG(LogLevel::INFO) << "accept success: " << addr.StringAddr();
                //多线程
                ThreadData* td = new ThreadData(sockfd, addr, this);
                pthread_t tid;
                pthread_create(&tid, nullptr, Routine, td);
            }
        }
        ~TcpServer()
        {

        }
    private:
        uint16_t _port;
        int _listensockerfd;
        func_t _f;
};